home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume25 / sybperl / part01 next >
Encoding:
Text File  |  1991-11-11  |  34.1 KB  |  1,299 lines

  1. Newsgroups: comp.sources.misc
  2. From: mpeppler@itf0.itf.ch (Michael Peppler)
  3. Subject:  v25i040:  sybperl - Sybase DB-Library extensions to Perl, Part01/01
  4. Message-ID: <1991Nov10.200558.23266@sparky.imd.sterling.com>
  5. X-Md4-Signature: d31b859697401b04dcea356a3727d11d
  6. Date: Sun, 10 Nov 1991 20:05:58 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: mpeppler@itf0.itf.ch (Michael Peppler)
  10. Posting-number: Volume 25, Issue 40
  11. Archive-name: sybperl/part01
  12. Environment: UNIX, Perl, Sybase
  13.  
  14. This is Sybperl, a set of subroutine extensions to Perl to interface
  15. directly to a Sybase dataserver.
  16.  
  17. Sybperl is very usefull for writing ad-hoc reports, when other tools
  18. are too cumbersome for the task. I use sybperl for all the reports in a
  19. production environment here at ITF Management.
  20.  
  21. Sybperl has been tested at a number of sites, and should work with no
  22. problem provided Perl works on your system.
  23.  
  24. Michael Peppler                 mpeppler@itf.ch {uunet,mcsun}!chsun!itf1!mpeppler
  25. ITF Management SA            BIX:   mpeppler                         
  26. 13 Rue de la Fontaine        Phone: (+4122) 312 1311  
  27. CH-1204 Geneva, Switzerland  Fax:   (+4122) 312 1322  
  28. ---------
  29. #! /bin/sh
  30. # This is a shell archive, meaning:
  31. # 1. Remove everything above the #! /bin/sh line.
  32. # 2. Save the resulting text in a file.
  33. # 3. Execute the file with /bin/sh (not csh) to create the files:
  34. #    README
  35. #    PACKING.LST
  36. #    BUGS
  37. #    Makefile
  38. #    sybperl.c
  39. #    sybperl.1
  40. #    patchlevel.h
  41. #    lib/sybperl.pl
  42. #    t/sbex.pl
  43. #
  44. # Wrapped by mpeppler@itf1.itf.ch on Mon Nov  4 16:34:43 MET 1991
  45. #
  46. if test -f 'README'
  47. then
  48.     echo shar: will not over-write existing file "'README'"
  49. else
  50.     echo x - 'README'
  51.     sed 's/^X//' >'README' << 'SHAR_EOF'
  52. X
  53. X                 Sybperl, version 1.0
  54. X
  55. X
  56. X
  57. X   Sybperl is a set of user-defined subroutines letting you access a
  58. X   Sybase data server using Perl.
  59. X
  60. X   Requirements: Perl ver 3.0.27 or higher.
  61. X         Sybase DB-Library (aka Open Client)
  62. X
  63. X
  64. X   Unshar somewhere convenient, and edit Makefile to reflect your
  65. X   system setup. The PERL_VERSION macro needs to be uncommented if you
  66. X   are compiling sybperl for Perl version 3.xx. The Makefile will not
  67. X   attempt to build uperl.o if it can't find it.
  68. X
  69. X   You'll also need to edit the lib/sybperl.pl file to addapt it to
  70. X   your environment.
  71. X
  72. X   There are some test scripts in the t directory which you can run to
  73. X   see if all is well, and to get an idea of what can be done with sybperl.
  74. X
  75. X   Sybperl has been tested succesfully in the following environments:
  76. X
  77. X   Sun Sparc, SunOS 4.1.1, Sybase 4.0.1, Perl 4.010
  78. X   Sun 3/80, SunOS 4.0.3, Sybase 4.0.1, Perl 4.010
  79. X   Sun Sparc, SunOS 4.1, Sybase 4.2, Perl 4.010
  80. X   Pyramid MIServer 2/2, OSx V5.1a, Sybase 4.0, Perl 4.010
  81. X   
  82. X   I use sybperl daily in a production environment on a Sun 4/65 under
  83. X   SunOS 4.1.1, with Sybase version 4.0.1.
  84. X
  85. X   BUGS:
  86. X
  87. X   There seems to be a major incompatibility between Perl and
  88. X   DB-Library, but I've been able to code around it. See the BUGS file
  89. X   for details.
  90. X
  91. X
  92. X
  93. X   Have fun using it and let me know of any improvements, problems,
  94. X   whatever...
  95. X
  96. X   Michael Peppler            mpeppler@itf.ch {uunet,mcsun}!chsun!itf1!mpeppler
  97. X   ITF Management SA            BIX:   mpeppler                         
  98. X   13 Rue de la Fontaine        Phone: (+4122) 312 1311  
  99. X   CH-1204 Geneva, Switzerland  Fax:   (+4122) 312 1322  
  100. X
  101. X   
  102. X
  103. X                   NOTICE - Warranty and Copyright
  104. X
  105. X           
  106. X   Sybperl is not a product of ITF Management. There is no warranty,
  107. X   and no official support.
  108. X
  109. X   Sybperl is copyright, but may be freely distributed under the
  110. X   same terms as Perl itself.
  111. X
  112. X
  113. X
  114. X   My thanks to the following people for testing Perl:
  115. X
  116. X   Teemu Torma
  117. X   Matthew Merzbacher
  118. X   Dan Banay
  119. X   Jeffrey Wong
  120. X   Anders Ardo
  121. X   Minh Ton Ha
  122. X   Gijs Mos
  123. X   G. Roderick Singleton
  124. X   Peter Gutmann
  125. X   
  126. SHAR_EOF
  127. if test 2105 -ne "`wc -c < 'README'`"
  128. then
  129.     echo shar: error transmitting "'README'" '(should have been 2105 characters)'
  130. fi
  131. fi
  132. chmod 664 README
  133. if test -f 'PACKING.LST'
  134. then
  135.     echo shar: will not over-write existing file "'PACKING.LST'"
  136. else
  137.     echo x - 'PACKING.LST'
  138.     sed 's/^X//' >'PACKING.LST' << 'SHAR_EOF'
  139. X
  140. X
  141. X    
  142. X    The Sybperl package should contain the following files:
  143. X
  144. X
  145. X        PACKING.LST        This file
  146. X        README        Read Me!
  147. X        BUGS        Perl/DB-library incompatibility descritpion
  148. X        Makefile
  149. X        sybperl.c        Sybperl source
  150. X        sybperl.1        Man page
  151. X        patchlevel.h
  152. X        t/sbex.pl        Example of sybperl script
  153. X        lib/sybperl.pl  A Perl library file.
  154. SHAR_EOF
  155. if test 358 -ne "`wc -c < 'PACKING.LST'`"
  156. then
  157.     echo shar: error transmitting "'PACKING.LST'" '(should have been 358 characters)'
  158. fi
  159. fi
  160. chmod 664 PACKING.LST
  161. if test -f 'BUGS'
  162. then
  163.     echo shar: will not over-write existing file "'BUGS'"
  164. else
  165.     echo x - 'BUGS'
  166.     sed 's/^X//' >'BUGS' << 'SHAR_EOF'
  167. X
  168. X    
  169. X    The Sybase DB-Library - Perl savestr() conflict
  170. X    ------------------------------------------------
  171. X
  172. X
  173. X    Ah! The joys of tying different packages together!
  174. X
  175. X    Both Perl and DB-Library have a function called savestr(). The
  176. X    DB-Library version is used in dbcmd() to add an SQL command to the
  177. X    list of commands pointed to by dpproc->dbcmdbuf, and in dbuse() as
  178. X    well. Now there are several ways to work around this problem.
  179. X
  180. X    1) Compile sybperl.c with -DBROKEN_DBCMD. I've written some code
  181. X       that emulates calls to dbcmd() and dbuse(). This works OK on my
  182. X       machine/OS/Version of Perl/Version of DBlib, but it relies on
  183. X       the internal storing method used by DBlib, and that might
  184. X       change in the future.
  185. X
  186. X    2) Recompile Perl (specifically, uperl.o in the Perl source
  187. X       directory) with some suitable flags (eg -Dsavestr=p_savestr).
  188. X       This does not create any compatibility problems, but is a
  189. X       lengthy procedure.
  190. X
  191. X    3) Do something like:
  192. X       cc -c sybperl.c
  193. X       ld -r -o sybperl2.o sybperl.o -lsybdb
  194. X       [edit sybperl2.o and replace `_savestr' with something like `_savest1']
  195. X       cc -o sybperl uperl.o sybperl2.o
  196. X       This is not a bad solution, but won't work if you have shared
  197. X       library versions of libsybdb.a
  198. X
  199. X    4) Edit uperl.o and replace savestr with something else. This is
  200. X       the solution I've chosen as the default. It is relatively fast,
  201. X       does not rely on any internal knowledge of DB-Library, and does
  202. X       not require Perl to be recompiled.
  203. X
  204. X    The Makefile gives some information on how to achieve these
  205. X    different options.
  206. X       
  207. X    Thanks to Teemu Torma for providing the initial input on this problem.    
  208. X
  209. X
  210. X    Michael
  211. SHAR_EOF
  212. if test 1734 -ne "`wc -c < 'BUGS'`"
  213. then
  214.     echo shar: error transmitting "'BUGS'" '(should have been 1734 characters)'
  215. fi
  216. fi
  217. chmod 664 BUGS
  218. if test -f 'Makefile'
  219. then
  220.     echo shar: will not over-write existing file "'Makefile'"
  221. else
  222.     echo x - 'Makefile'
  223.     sed 's/^X//' >'Makefile' << 'SHAR_EOF'
  224. X#    @(#)Makefile    1.4    9/9/91
  225. X#
  226. X    
  227. XCC = cc
  228. XPERLSRC = ..                # where to find uperl.o
  229. XSYBINCS = /usr/local/sybase/include    # where to find the sybase .h files
  230. XLOCINCS =                # other includes ?
  231. XSYBLIBDIR = /usr/local/lib        # Sybase libraries
  232. XSYBLIBS = -lsybdb            # db-library
  233. X
  234. X# Uncomment this if you are compiling sybperl for Perl version 3.xx
  235. X
  236. X# PERL_VERSION = -DVERSION3
  237. X
  238. X# The Perl/Sybase savestr() conflict.
  239. X# Both Perl and Sybase DB-Library have a function called savestr(),
  240. X# and this creates a problem when using functions such as dbcmd().
  241. X# There are several ways around this.
  242. X# You can:
  243. X#
  244. X#    - define BROKEN_DBCMD: this enables some code emulating
  245. X#      dbcmd() that I've written.
  246. X#    - Recompile uperl.o with a -Dsavestr=psvestr (or something similar).
  247. X#    - Edit an existing uperl.o and change _savestr to _psvestr.
  248. X#
  249. X# To use the first option, uncomment the following definitions for
  250. X# SAVESTR and UPERL
  251. X# SAVESTR = -DBROKEN_DBCMD
  252. X# UPERL = $(PERLSRC)/uperl.o
  253. X#
  254. X# To use the second option, you have to reconfigure & recompile Perl
  255. X# manually, and then set compile sybperl with the following line
  256. X# uncommented:
  257. X# UPERL = $(PERLSRC)/uperl.o
  258. X#
  259. X# The default is to use the third solution:
  260. XUPERL = uperl2.o
  261. X
  262. X
  263. XCFLAGS = -O                 # 
  264. XCPPFLAGS = -I$(PERLSRC) -I$(LOCINCS) -I$(SYBINCS) $(PERL_VERSION) $(SAVESTR)
  265. XBINDIR = /usr/local/bin            # where does the executable go
  266. XPERLLIB = /usr/local/lib/perl        # where does lib/sybperl.pl go
  267. XMANDIR = /usr/local/man            # where do we put the manual page
  268. XMANEXT = l
  269. X
  270. X
  271. Xsybperl: $(UPERL) sybperl.o
  272. X    $(CC) $(CFLAGS) -L$(SYBLIBDIR) $(UPERL) sybperl.o $(SYBLIBS) -lm -o sybperl
  273. X
  274. Xsybperl.o: sybperl.c
  275. X    $(CC) -c $(CFLAGS) $(CPPFLAGS) sybperl.c
  276. X
  277. X# Create uperl.o IF you wish to use the 3rd way of resolving the
  278. X# Perl/Sybase savestr conflict.
  279. X$(UPERL): $(PERLSRC)/uperl.o
  280. X    cp $(PERLSRC)/uperl.o $(UPERL)
  281. X    perl -p -i.bak -e 's/savestr/psvestr/g;' $(UPERL)
  282. X
  283. Xclean:
  284. X    rm -f sybperl *.o *~
  285. X
  286. Xinstall: sybperl
  287. X    install -s -m 775 sybperl $(BINDIR)
  288. X    cp lib/sybperl.pl $(PERLLIB)/perllib.pl
  289. X    pc sybperl.1 $(MANDIR)/man$(MANEXT)/sybperl.$(MANEXT)
  290. X
  291. Xshar:
  292. X    rm -f sybperl.shar
  293. X    shar.pl README PACKING.LST BUGS Makefile sybperl.c sybperl.1 patchlevel.h lib/sybperl.pl t/sbex.pl >sybperl.shar
  294. X
  295.  
  296. SHAR_EOF
  297. if test 2188 -ne "`wc -c < 'Makefile'`"
  298. then
  299.     echo shar: error transmitting "'Makefile'" '(should have been 2188 characters)'
  300. fi
  301. fi
  302. chmod 444 Makefile
  303. if test -f 'sybperl.c'
  304. then
  305.     echo shar: will not over-write existing file "'sybperl.c'"
  306. else
  307.     echo x - 'sybperl.c'
  308.     sed 's/^X//' >'sybperl.c' << 'SHAR_EOF'
  309. Xstatic char SccsId[] = "@(#)sybperl.c    1.5    9/9/91";
  310. X/************************************************************************/
  311. X/*    Copyright 1991 by Michael Peppler and ITF Management SA     */
  312. X/*                                    */
  313. X/*    Full ownership of this software, and all rights pertaining to     */
  314. X/*    the for-profit distribution of this software, are retained by     */
  315. X/*    Michael Peppler and ITF Management SA.  You are permitted to     */
  316. X/*    use this software without fee.  This software is provided "as     */
  317. X/*    is" without express or implied warranty.  You may redistribute     */
  318. X/*    this software, provided that this copyright notice is retained,    */
  319. X/*    and that the software is not distributed for profit.  If you     */
  320. X/*    wish to use this software in a profit-making venture, you must     */
  321. X/*    first license this code and its underlying technology from     */
  322. X/*    ITF Management SA.                         */
  323. X/*                                    */
  324. X/*    Bottom line: you can have this software, you can use it, you     */
  325. X/*    can give it away.  You just can't sell any or all parts of it     */
  326. X/*    without prior permission from Harris Corporation.         */
  327. X/************************************************************************/
  328. X
  329. X/* sybase.c
  330. X *
  331. X * Call Sybase DB-Library functions from Perl.
  332. X * Written by Michael Peppler (mpeppler@itf.ch)
  333. X * ITF Management SA, 13 rue de la Fontaine
  334. X * CH-1204 Geneva, Switzerland
  335. X * Tel: (+4122) 312 1311 Fax: (+4122) 312 1322
  336. X */
  337. X
  338. X/* 
  339. X * The Perl/Sybase savestr() conflict.
  340. X * Both Perl and Sybase DB-Library have a function called savestr(). 
  341. X * This creates a problem when calling dbcmd() and dbuse(). There are 
  342. X * several ways to work around this, one of which is to #define 
  343. X * BROKEN_DBCMD, which enables some code that I've written to simulate 
  344. X * dbcmd() locally. See Makefile and BUGS for details.
  345. X */
  346. X#include "EXTERN.h"
  347. X#include "perl.h"
  348. X#undef MAX
  349. X#undef MIN
  350. X
  351. X#if !defined(VERSION3)
  352. X#define str_2static(s)        str_2mortal(s)
  353. X#endif
  354. X
  355. X#include <sybfront.h>
  356. X#include <sybdb.h>
  357. X#include <syberror.h>
  358. X
  359. X#include "patchlevel.h"
  360. X
  361. Xextern int wantarray;
  362. X
  363. Xchar *savestr();
  364. X
  365. X
  366. X/* 
  367. X * The variables that the Sybase routines set, and that you may want 
  368. X * to test in your Perl script. These variables are READ-ONLY.
  369. X */
  370. Xstatic enum uservars
  371. X{
  372. X    UV_SUCCEED,            /* Returns SUCCEED */
  373. X    UV_FAIL,            /* Returns FAIL */
  374. X    UV_NO_MORE_ROWS,        /* Returns NO_MORE_ROWS */
  375. X    UV_NO_MORE_RESULTS,        /* Returns NO_MORE_RESULTS */
  376. X    UV_ComputeId,        /* Returns the compute id of the row (in dbnextrow()) */
  377. X    UV_SybperlVer,        /* Returns Sybperl Version/Patchlevel */
  378. X};
  379. X
  380. X/* 
  381. X * User subroutines that we have implemented. I've found that I can do 
  382. X * all the stuff I want to with this subset of DB-Library. Let me know 
  383. X * if you implement further routines.
  384. X * The names are self-explanatory.
  385. X */
  386. Xstatic enum usersubs
  387. X{
  388. X    US_dblogin,            /* This also performs a dbopen()  */
  389. X    US_dbopen,
  390. X    US_dbclose,
  391. X    US_dbcmd,
  392. X    US_dbsqlexec,
  393. X    US_dbresults,
  394. X    US_dbnextrow,
  395. X    US_dbcancel,
  396. X    US_dbcanquery,
  397. X    US_dbexit,
  398. X    US_dbuse,
  399. X};
  400. X
  401. X#define MAX_DBPROCS 25        /* Change this if you really want your perl script to talk to */
  402. X                /* more than 25 dataserver connections at a time ...*/
  403. X
  404. Xstatic LOGINREC *login;
  405. Xstatic DBPROCESS *dbproc[MAX_DBPROCS];
  406. Xstatic int exitCalled = 0;    /* Set to 1 if dbexit() has been called. */
  407. Xstatic int ComputeId;
  408. X
  409. Xstatic int usersub();
  410. Xstatic int userset();
  411. Xstatic int userval();
  412. Xstatic int err_handler(), msg_handler();
  413. X
  414. Xint userinit()
  415. X{
  416. X    init_sybase();
  417. X}
  418. X
  419. Xint
  420. Xinit_sybase()
  421. X{
  422. X    struct ufuncs uf;
  423. X    char *filename = "sybase.c";
  424. X
  425. X    if (dbinit() == FAIL)    /* initialize dblibrary */
  426. X    exit(ERREXIT);
  427. X/*
  428. X * Install the user-supplied error-handling and message-handling routines.
  429. X * They are defined at the bottom of this source file.
  430. X */
  431. X    dberrhandle(err_handler);
  432. X    dbmsghandle(msg_handler);
  433. X    
  434. X    uf.uf_set = userset;
  435. X    uf.uf_val = userval;
  436. X
  437. X#define MAGICVAR(name, ix) uf.uf_index = ix, magicname(name, &uf, sizeof uf)
  438. X
  439. X    MAGICVAR("SUCCEED",    UV_SUCCEED);
  440. X    MAGICVAR("FAIL",UV_FAIL);
  441. X    MAGICVAR("NO_MORE_ROWS",    UV_NO_MORE_ROWS);
  442. X    MAGICVAR("NO_MORE_RESULTS",    UV_NO_MORE_RESULTS);
  443. X    MAGICVAR("ComputeId",    UV_ComputeId);
  444. X    MAGICVAR("SybperlVer",    UV_SybperlVer);
  445. X
  446. X    make_usub("dblogin",    US_dblogin,    usersub, filename);
  447. X    make_usub("dbopen",        US_dbopen,    usersub, filename);
  448. X    make_usub("dbclose",    US_dbclose,    usersub, filename);
  449. X    make_usub("dbcmd",        US_dbcmd,    usersub, filename);
  450. X    make_usub("dbsqlexec",    US_dbsqlexec,    usersub, filename);
  451. X    make_usub("dbresults",    US_dbresults,    usersub, filename);
  452. X    make_usub("dbnextrow",    US_dbnextrow,    usersub, filename);
  453. X    make_usub("dbcancel",    US_dbcancel,    usersub, filename);
  454. X    make_usub("dbcanquery",    US_dbcanquery,    usersub, filename);
  455. X    make_usub("dbexit",    US_dbexit,    usersub, filename);
  456. X    make_usub("dbuse",    US_dbuse,    usersub, filename);
  457. X
  458. X}
  459. X
  460. Xstatic int
  461. Xusersub(ix, sp, items)
  462. Xint ix;
  463. Xregister int sp;
  464. Xregister int items;
  465. X{
  466. X    STR **st = stack->ary_array + sp;
  467. X    ARRAY *ary = stack;    
  468. X    register int i;
  469. X    register STR *Str;        /* used in str_get and str_gnum macros */
  470. X    int inx = -1;        /* Index into dbproc[] array. Passed as first parameter to nearly all &dbxxx() calls */
  471. X
  472. X    if(exitCalled)
  473. X    fatal("&dbexit() has been called. Access to Sybase impossible.");
  474. X
  475. X    switch (ix)
  476. X    {
  477. X      case US_dblogin:
  478. X    if (items > 2)
  479. X        fatal("Usage: &dblogin([user[,pwd]])");
  480. X    if (login)
  481. X        fatal("&dblogin() called twice.");
  482. X    else
  483. X    {
  484. X        int retval;
  485. X
  486. X        login = dblogin();
  487. X        if(items)
  488. X        {
  489. X        DBSETLUSER(login, (char *)str_get(st[1]));
  490. X        if(items > 1)
  491. X            DBSETLPWD(login, (char *)str_get(st[2]));
  492. X        }
  493. X
  494. X        dbproc[0] = dbopen(login, NULL);
  495. X        str_numset(st[0], (double) 0);
  496. X    }
  497. X    break;
  498. X      case US_dbopen:
  499. X    if (items != 0)
  500. X        fatal("Usage: $dbproc = &dbopen;");
  501. X    else
  502. X    {
  503. X        int j;
  504. X
  505. X        for(j = 0; j < MAX_DBPROCS; ++j)
  506. X        if(dbproc[j] == NULL)
  507. X            break;
  508. X        if(j == MAX_DBPROCS)
  509. X        fatal("&dbopen: No more dbprocs available.");
  510. X        dbproc[j] = dbopen(login, NULL);
  511. X        str_numset(st[0], (double) j);
  512. X    }
  513. X    break;
  514. X      case US_dbclose:
  515. X    if (items != 1)
  516. X        fatal("Usage: $ret = &dbclose($dbproc);");
  517. X    else
  518. X    {
  519. X        inx = getDbProc(st[1]);
  520. X
  521. X        dbclose(dbproc[inx]);
  522. X        dbproc[inx] = (DBPROCESS *)NULL;
  523. X    }
  524. X    break;
  525. X      case US_dbcancel:
  526. X    if (items != 1)
  527. X        fatal("Usage: &dbcancel($dbproc)");
  528. X    else
  529. X    {
  530. X        int retval;
  531. X#if defined(BROKEN_DBCMD)
  532. X        DBSTRING *ptr;
  533. X        DBSTRING *old;
  534. X#endif
  535. X        inx = getDbProc(st[1]);
  536. X
  537. X        retval = dbcancel(dbproc[inx]);
  538. X        str_numset(st[0], (double) retval);
  539. X#if defined(BROKEN_DBCMD)
  540. X        ptr = dbproc[inx]->dbcmdbuf;
  541. X        while(ptr)
  542. X        {
  543. X        old = ptr;
  544. X        ptr = ptr->strnext;
  545. X        free(old->strtext);
  546. X        free(old);
  547. X        }
  548. X        dbproc[inx]->dbcmdbuf = NULL;
  549. X#endif
  550. X    }
  551. X    break;
  552. X
  553. X      case US_dbcanquery:
  554. X    if (items != 1)
  555. X        fatal("Usage: &dbcanquery($dbproc)");
  556. X    else
  557. X    {
  558. X        int retval;
  559. X        inx = getDbProc(st[1]);
  560. X
  561. X        retval = dbcanquery(dbproc[inx]);
  562. X        str_numset(st[0], (double) retval);
  563. X    }
  564. X    break;
  565. X
  566. X      case US_dbexit:
  567. X    if (items != 0)
  568. X        fatal("Usage: &dbexit()");
  569. X    else
  570. X    {
  571. X        dbexit(dbproc[0]);
  572. X        exitCalled++;
  573. X        str_numset(st[0], (double) 1);
  574. X    }
  575. X    break;
  576. X
  577. X      case US_dbuse:
  578. X    if (items != 2)
  579. X        fatal("Usage: &dbuse($dbproc, $database)");
  580. X    else
  581. X    {
  582. X#if defined(BROKEN_DBCMD)
  583. X        /* 
  584. X         * Why doesn't this $@#! dbuse() call not work from within 
  585. X         * Perl????? (So we emulate it here, but I sure can't 
  586. X         * guarantee anything about portability to future versions 
  587. X         * of DB-Library!
  588. X         */
  589. X        DBSTRING *new;
  590. X        DBSTRING *sav;
  591. X        char *strdup();
  592. X        char buff[256];
  593. X        int ret;
  594. X
  595. X        inx = getDbProc(st[1]);
  596. X
  597. X        strcpy(buff, "use ");
  598. X        strcat(buff, (char *)str_get(st[2]));
  599. X        sav = dbproc[inx]->dbcmdbuf;
  600. X
  601. X        new = (DBSTRING *)calloc(1,sizeof(DBSTRING));
  602. X        new->strtext = (BYTE *)strdup((char *)buff);
  603. X        new->strtotlen = strlen(new->strtext)+1;
  604. X        dbproc[inx]->dbcmdbuf = new;
  605. X
  606. X        ret = dbsqlexec(dbproc[inx]);
  607. X        ret = dbresults(dbproc[inx]);
  608. X        while((ret = dbnextrow(dbproc[inx])) != NO_MORE_ROWS)
  609. X        ;
  610. X
  611. X        free(new->strtext);
  612. X        free(new);
  613. X        
  614. X        dbproc[inx]->dbcmdbuf = sav;
  615. X        str_numset(st[0], (double) SUCCEED);
  616. X#else
  617. X        int retval;
  618. X        char str[255];
  619. X        strcpy(str, (char *)str_get(st[2]));
  620. X        inx = getDbProc(st[1]);
  621. X
  622. X        retval = dbuse(dbproc[inx], str);
  623. X        str_numset(st[0], (double) retval);
  624. X#endif
  625. X    }
  626. X    break;
  627. X
  628. X      case US_dbsqlexec:
  629. X    if (items != 1)
  630. X        fatal("Usage: &dbsqlexec($dbproc)");
  631. X    else
  632. X    {
  633. X        int retval;
  634. X        inx = getDbProc(st[1]);
  635. X
  636. X        retval = dbsqlexec(dbproc[inx]);
  637. X        str_numset(st[0], (double) retval);
  638. X    }
  639. X    break;
  640. X
  641. X      case US_dbresults:
  642. X    if (items != 1)
  643. X        fatal("Usage: &dbresults($dbproc)");
  644. X    else
  645. X    {
  646. X        int retval;
  647. X        inx = getDbProc(st[1]);
  648. X
  649. X        retval = dbresults(dbproc[inx]);
  650. X        str_numset(st[0], (double) retval);
  651. X#if defined(BROKEN_DBCMD)
  652. X        if(retval==NO_MORE_RESULTS)
  653. X        {
  654. X        DBSTRING *ptr = dbproc[inx]->dbcmdbuf;
  655. X        DBSTRING *old;
  656. X
  657. X        while(ptr)
  658. X        {
  659. X            old = ptr;
  660. X            ptr = ptr->strnext;
  661. X            free(old->strtext);
  662. X            free(old);
  663. X        }
  664. X        dbproc[inx]->dbcmdbuf = NULL;
  665. X        }
  666. X#endif
  667. X    }
  668. X    break;
  669. X
  670. X      case US_dbcmd:
  671. X    if (items != 2)
  672. X        fatal("Usage: &dbcmd($dbproc, $str)");
  673. X    else
  674. X    {
  675. X        int retval;
  676. X#if defined(BROKEN_DBCMD)
  677. X        DBSTRING *ptr;
  678. X        DBSTRING *new, *old;
  679. X        char *strdup();
  680. X#endif
  681. X        inx = getDbProc(st[1]);
  682. X        
  683. X#if defined(BROKEN_DBCMD)
  684. X        ptr = dbproc[inx]->dbcmdbuf;
  685. X
  686. X        new = (DBSTRING *)calloc(1,sizeof(DBSTRING));
  687. X        new->strtext = (BYTE *)strdup((char *)str_get(st[2]));
  688. X        new->strtotlen = strlen(new->strtext)+1;
  689. X        if(!ptr)
  690. X        dbproc[inx]->dbcmdbuf = new;
  691. X        else
  692. X        {
  693. X        while(ptr->strnext)
  694. X            ptr = ptr->strnext;
  695. X        ptr->strnext = new;
  696. X        }
  697. X#else
  698. X        retval = dbcmd(dbproc[inx], (char *)str_get(st[2]));
  699. X#endif
  700. X        str_numset(st[0], (double) retval);
  701. X    }
  702. X    break;
  703. X
  704. X    case US_dbnextrow:
  705. X    if (items != 1)
  706. X        fatal("Usage: @arr = &dbnextrow($dbproc)");
  707. X    else
  708. X    {
  709. X        int retval;
  710. X        inx = getDbProc(st[1]);
  711. X
  712. X        --sp;        /* otherwise you get an empty element at the beginning of the results array! */
  713. X
  714. X        retval = dbnextrow(dbproc[inx]);
  715. X        if(retval == REG_ROW)
  716. X        {
  717. X            char buff[1024], *p;
  718. X        BYTE *data;
  719. X        int col, type, numcols = dbnumcols(dbproc[inx]);
  720. X        int len;
  721. X        DBFLT8 tmp;
  722. X
  723. X        ComputeId = 0;
  724. X
  725. X        for(col = 1, buff[0] = 0; col <= numcols; ++col)
  726. X        {
  727. X            type = dbcoltype(dbproc[inx], col);
  728. X            len = dbdatlen(dbproc[inx],col);
  729. X            data = (BYTE *)dbdata(dbproc[inx],col);
  730. X            if(!data && !len)
  731. X            {
  732. X            strcpy(buff,"NULL");
  733. X            }
  734. X            else
  735. X            {
  736. X            switch(type)
  737. X            {
  738. X              case SYBCHAR:
  739. X                strncpy(buff,data,len);
  740. X                buff[len] = 0;
  741. X                break;
  742. X              case SYBINT1:
  743. X              case SYBBIT: /* a bit is at least a byte long... */
  744. X                sprintf(buff,"%u",*(unsigned char *)data);
  745. X                break;
  746. X              case SYBINT2:
  747. X                sprintf(buff,"%d",*(short *)data);
  748. X                break;
  749. X              case SYBINT4:
  750. X                sprintf(buff,"%d",*(long *)data);
  751. X                break;
  752. X              case SYBFLT8:
  753. X                sprintf(buff,"%.6f",*(double *)data);
  754. X                break;
  755. X              case SYBMONEY:
  756. X                dbconvert(dbproc[inx], SYBMONEY, data,-1,SYBFLT8,&tmp,-1);
  757. X                sprintf(buff,"%.6f",tmp);
  758. X                break;
  759. X              case SYBDATETIME:
  760. X                dbconvert(dbproc[inx], SYBDATETIME, data,-1,SYBCHAR,buff,-1);
  761. X                break;
  762. X              default:
  763. X                /* ignored at the moment... */
  764. X                break;
  765. X            }
  766. X            }
  767. X            (void)astore(ary,++sp,str_2static(str_make(buff,0)));
  768. X        }
  769. X        }
  770. X        if (retval > 0)
  771. X        {
  772. X            char buff[1024], *p;
  773. X        BYTE *data;
  774. X        int col, type, numcols;
  775. X        int len;
  776. X        DBFLT8 tmp;
  777. X
  778. X        ComputeId = retval;
  779. X        numcols = dbnumalts(dbproc[inx], ComputeId);
  780. X
  781. X        for(col = 1, buff[0] = 0; col <= numcols; ++col)
  782. X        {
  783. X            type = dbalttype(dbproc[inx], ComputeId, col);
  784. X            len = dbadlen(dbproc[inx], ComputeId, col);
  785. X            data = (BYTE *)dbadata(dbproc[inx], ComputeId, col);
  786. X            if(!data && !len)
  787. X            {
  788. X            strcpy(buff,"NULL");
  789. X            }
  790. X            else
  791. X            {
  792. X            switch(type)
  793. X            {
  794. X              case SYBCHAR:
  795. X                strncpy(buff,data,len);
  796. X                buff[len] = 0;
  797. X                break;
  798. X              case SYBINT1:
  799. X              case SYBBIT: /* a bit is at least a byte long... */
  800. X                sprintf(buff,"%d",*(char *)data);
  801. X                break;
  802. X              case SYBINT2:
  803. X                sprintf(buff,"%d",*(short *)data);
  804. X                break;
  805. X              case SYBINT4:
  806. X                sprintf(buff,"%d",*(long *)data);
  807. X                break;
  808. X              case SYBFLT8:
  809. X                sprintf(buff,"%.6f",*(double *)data);
  810. X                break;
  811. X              case SYBMONEY:
  812. X                dbconvert(dbproc[inx], SYBMONEY, data,-1,SYBFLT8,&tmp,-1);
  813. X                sprintf(buff,"%.6f",tmp);
  814. X                break;
  815. X              case SYBDATETIME:
  816. X                dbconvert(dbproc[inx], SYBDATETIME, data,-1,SYBCHAR,buff,-1);
  817. X                break;
  818. X              default:
  819. X                /* ignored at the moment... */
  820. X                break;
  821. X            }
  822. X            }
  823. X            (void)astore(ary,++sp,str_2static(str_make(buff,0)));
  824. X        }
  825. X        }        
  826. X#if defined(BROKEN_DBCMD)
  827. X        /* 
  828. X         * We can't rely on dbcmd(),dbresults() etc. to clean up 
  829. X         * the dbcmdbuf linked list, so we have to it ourselves...
  830. X         */
  831. X        if(retval == NO_MORE_ROWS && !DBMORECMDS(dbproc[inx]))
  832. X        {
  833. X        DBSTRING *ptr = dbproc[inx]->dbcmdbuf;
  834. X        DBSTRING *new, *old;
  835. X
  836. X        while(ptr)
  837. X        {
  838. X            old = ptr;
  839. X            ptr = ptr->strnext;
  840. X            free(old->strtext);
  841. X            free(old);
  842. X        }
  843. X        dbproc[inx]->dbcmdbuf = NULL;
  844. X        }
  845. X#endif
  846. X    }
  847. X    break;
  848. X
  849. X    default:
  850. X    fatal("Unimplemented user-defined subroutine");
  851. X    }
  852. X    return sp;
  853. X}
  854. X
  855. X/* 
  856. X * Return the value of a userdefined variable. These variables are all 
  857. X * READ-ONLY in Perl.
  858. X */
  859. Xstatic int
  860. Xuserval(ix, str)
  861. Xint ix;
  862. XSTR *str;
  863. X{
  864. X    char buff[24];
  865. X    
  866. X    switch (ix)
  867. X    {
  868. X      case UV_SUCCEED:
  869. X    str_numset(str, (double)SUCCEED);
  870. X    break;
  871. X      case UV_FAIL:
  872. X    str_numset(str, (double)FAIL);
  873. X    break;
  874. X      case UV_NO_MORE_ROWS:
  875. X    str_numset(str, (double)NO_MORE_ROWS);
  876. X    break;
  877. X      case UV_NO_MORE_RESULTS:
  878. X    str_numset(str, (double)NO_MORE_RESULTS);
  879. X    break;
  880. X      case UV_ComputeId:
  881. X    str_numset(str, (double)ComputeId);
  882. X    break;
  883. X      case UV_SybperlVer:
  884. X    sprintf(buff, "%d.%3.3d", VERSION, PATCHLEVEL);
  885. X    str_set(str, buff);
  886. X    break;
  887. X    }
  888. X    return 0;
  889. X}
  890. X
  891. Xstatic int
  892. Xuserset(ix, str)        /* Not used. None of these variables are user-settable */
  893. Xint ix;
  894. XSTR *str;
  895. X{
  896. X    return 0;
  897. X}
  898. X
  899. X
  900. X/*ARGSUSED*/
  901. Xstatic int err_handler(dbprocl, severity, dberr, oserr, dberrstring, oserrstr)
  902. X    DBPROCESS *dbprocl;
  903. X    int severity;
  904. X    int dberr;
  905. X    int oserr;
  906. X    char *dberrstring;
  907. X    char *oserrstr;
  908. X{
  909. X    if ((dbprocl == NULL) || (DBDEAD(dbprocl)))
  910. X    return(INT_EXIT);
  911. X    else 
  912. X    {
  913. X    fprintf(stderr,"DB-Library error:\n\t%s\n", dberrstring);
  914. X    
  915. X    if (oserr != DBNOERR)
  916. X        fprintf(stderr,"Operating-system error:\n\t%s\n", oserrstr);
  917. X    
  918. X    return(INT_CANCEL);
  919. X    }
  920. X}
  921. X
  922. X/*ARGSUSED*/
  923. X
  924. Xstatic int msg_handler(dbprocl, msgno, msgstate, severity, msgtext, srvname, procname, Line)
  925. X    DBPROCESS *dbprocl;
  926. X    DBINT msgno;
  927. X    int msgstate;
  928. X    int severity;
  929. X    char *msgtext;
  930. X    char *srvname;
  931. X    char *procname;
  932. X    DBUSMALLINT Line;
  933. X{
  934. X    if(msgno != 5701)        /* Ignore 'Changed database context' messages */
  935. X    {
  936. X    fprintf (stderr,"Msg %ld, Level %d, State %d\n", 
  937. X         msgno, severity, msgstate);
  938. X    if (strlen(srvname) > 0)
  939. X        fprintf (stderr,"Server '%s', ", srvname);
  940. X    if (strlen(procname) > 0)
  941. X        fprintf (stderr,"Procedure '%s', ", procname);
  942. X    if (Line > 0)
  943. X        fprintf (stderr,"Line %d", Line);
  944. X    
  945. X    fprintf(stderr,"\n\t%s\n", msgtext);
  946. X    }
  947. X    
  948. X    if(severity)
  949. X    exit(-1);
  950. X    
  951. X    return(0);
  952. X}
  953. X
  954. X/* 
  955. X * Get the index into the dbproc[] array from a Perl STR datatype. 
  956. X * Check that the index is reasonably valid...
  957. X */
  958. Xint getDbProc(Str)
  959. X    STR *Str;
  960. X{
  961. X    int ix = (int)str_gnum(Str);
  962. X
  963. X    if(ix < 0 || ix >= MAX_DBPROCS)
  964. X    fatal("$dbproc parameter is out of range.");
  965. X    return ix;
  966. X}
  967. X    
  968.  
  969. SHAR_EOF
  970. if test 15591 -ne "`wc -c < 'sybperl.c'`"
  971. then
  972.     echo shar: error transmitting "'sybperl.c'" '(should have been 15591 characters)'
  973. fi
  974. fi
  975. chmod 444 sybperl.c
  976. if test -f 'sybperl.1'
  977. then
  978.     echo shar: will not over-write existing file "'sybperl.1'"
  979. else
  980.     echo x - 'sybperl.1'
  981.     sed 's/^X//' >'sybperl.1' << 'SHAR_EOF'
  982. X.\".po 4
  983. X.TH SYBPERL 1 "3 September 1991"
  984. X.ad
  985. X.nh
  986. X.SH NAME
  987. Xsybperl \- Perl access to Sybase databases
  988. X.SH SYNOPSIS
  989. X.nf
  990. X$dbproc  = &dblogin([$user[, $pwd]])
  991. X$dbproc1 = &dbopen()
  992. X       &dbclose($dbproc)
  993. X$ret     = &dbcmd($dbproc, $sql_cmd)
  994. X$ret     = &dbsqlexec($dbproc)
  995. X$ret     = &dbresults($dbproc)
  996. X@data    = &dbnextrow($dbproc)
  997. X$ret     = &dbuse($dbproc, $database)
  998. X$ret     = &dbcancel($dbproc)
  999. X$ret     = &dbcanquery($dbproc)
  1000. X$ret     = &dbexit($dbproc)
  1001. X
  1002. X$SUCCEED
  1003. X$FAIL
  1004. X$NO_MORE_ROWS
  1005. X$NO_MORE_RESULTS
  1006. X$ComputeId
  1007. X$SybperlVer
  1008. X.fi
  1009. X.SH DESCRIPTION
  1010. X\fBSybperl\fP is a version of \fIPerl\fP which has been extended (via
  1011. Xthe \fIusersubs\fP feature) to allow access to \fISybase\fP databases.
  1012. X.SH Functions
  1013. X\fBSybperl\fP basically maps the calls existing in the \fISybase
  1014. XDB-Library\fP to \fIPerl\fP. The usage of these fcuntions is the same
  1015. Xas in \fIDB-Library\fP, unless specifically noted.
  1016. X
  1017. XThe following functions are provided:
  1018. X
  1019. X.nf
  1020. X\fB$dbproc  = &dblogin([$user[, $pwd]])\fP
  1021. X\fB&dbproc1 = &dbopen()\fP
  1022. X\fB          &dbclose($dbproc)\fP
  1023. X\fB$status  = &dbcmd($dbproc, $sql_cmd)\fP
  1024. X\fB$status  = &dbsqlexec($dbproc)\fP
  1025. X\fB$status  = &dbresults($dbproc)\fP
  1026. X\fB@data    = &dbnextrow($dbproc)\fP
  1027. X\fB$status  = &dbuse($dbproc, $database)\fP
  1028. X\fB$status  = &dbcancel($dbproc)\fP
  1029. X\fB$status  = &dbcanquery($dbproc)\fP
  1030. X\fB$status  = &dbexit($dbproc)\fP
  1031. X.fi
  1032. X
  1033. XDifferences with DB-Library:
  1034. X
  1035. X\fB&dblogin\fP takes 2 optional arguements (the userid and the
  1036. Xpassword). These default to the Unix userid, and the null password.
  1037. X
  1038. X\fB&dblogin\fP returns a \fBDBPROCESS\fP, not a \fBLOGINREC\fP. This
  1039. Xsimplifies the call to open a connection to a Sybase dataserver
  1040. Xsomewhat. Further \fBDBPROCESSes\fP can be opened using
  1041. X\fB&dbopen()\fP (No arguments). The number of simultaneous DBPROCESSes
  1042. Xis limited to 25 (This can be changed by altering a #define in sybperl.c).
  1043. X
  1044. X\fB&dbnextrow\fP returns an array of formatted data, based on the
  1045. Xdatatype of the corresponding columns. \fB&dbnextrow\fP sets the
  1046. Xvariable \fB$ComputeId\fP when the result row is a computed row (the
  1047. Xresult of a \fIcompute by\fP clause).
  1048. X
  1049. X.SH "UNIMPLEMENTED FEATURES"
  1050. X
  1051. XThe \fBSYBIMAGE\fP and \fBSYBTEXT\fP are not implemented.
  1052. X
  1053. X\fB&dbfcmd\fP is not implemented, but can be emulated by using
  1054. X\fIsprintf\fP as in \fI&dbcmd($dbproc, sprintf("%d", $num_val))\;\fP
  1055. X
  1056. XOne cannot log in to a specific server (ie \fIdbopen()\fP is always
  1057. Xcalled with a \fINULL\fP second parameter.
  1058. X
  1059. X.SH OPTIONS
  1060. X
  1061. XSee the \fIPerl(1)\fP manual page.
  1062. X
  1063. X.SH FILES
  1064. X
  1065. X\fI$PERLLIB/sybperl.pl\fP should be called in all \fBsybperl\fP
  1066. Xscripts to set the correct environment variables used by DB-Library.
  1067. X
  1068. X.SH "SEE ALSO"
  1069. X
  1070. X\fIPerl(1), Sybase Open Client DB Library Reference Manual.\fP
  1071. X
  1072. X.SH AUTHOR
  1073. X
  1074. XMichael Peppler, ITF Management SA \- mpeppler@itf.ch
  1075. SHAR_EOF
  1076. if test 2755 -ne "`wc -c < 'sybperl.1'`"
  1077. then
  1078.     echo shar: error transmitting "'sybperl.1'" '(should have been 2755 characters)'
  1079. fi
  1080. fi
  1081. chmod 664 sybperl.1
  1082. if test -f 'patchlevel.h'
  1083. then
  1084.     echo shar: will not over-write existing file "'patchlevel.h'"
  1085. else
  1086.     echo x - 'patchlevel.h'
  1087.     sed 's/^X//' >'patchlevel.h' << 'SHAR_EOF'
  1088. X#define VERSION 1
  1089. X#define PATCHLEVEL 3
  1090.  
  1091. SHAR_EOF
  1092. if test 40 -ne "`wc -c < 'patchlevel.h'`"
  1093. then
  1094.     echo shar: error transmitting "'patchlevel.h'" '(should have been 40 characters)'
  1095. fi
  1096. fi
  1097. chmod 664 patchlevel.h
  1098. if test ! -d 'lib'
  1099. then
  1100.     mkdir 'lib'
  1101. fi
  1102. if test -f 'lib/sybperl.pl'
  1103. then
  1104.     echo shar: will not over-write existing file "'lib/sybperl.pl'"
  1105. else
  1106.     echo x - 'lib/sybperl.pl'
  1107.     sed 's/^X//' >'lib/sybperl.pl' << 'SHAR_EOF'
  1108. X;#     @(#)sybperl.pl    1.1    9/3/91
  1109. X
  1110. X;# This file, when interpreted, sets the appropriate environment
  1111. X;# variables for Sybase's use DB-Library & isql.
  1112. X;#
  1113. X;# usage:
  1114. X;#    require 'sybperl.pl';
  1115. X;#
  1116. X;# We don't set the environment if it is already set.
  1117. X
  1118. X
  1119. X$ENV{'SYBASE'} = "/usr/local/sybase" unless $ENV{'SYBASE'};
  1120. X$ENV{'DSQUERY'}= "SYBASE" unless $ENV{'DSQUERY'};
  1121. X$ENV{'PATH'}="$ENV{'PATH'}:$ENV{'SYBASE'}/bin" unless $ENV{'PATH'} =~ /$ENV{'SYBASE'}/;
  1122.  
  1123. SHAR_EOF
  1124. if test 441 -ne "`wc -c < 'lib/sybperl.pl'`"
  1125. then
  1126.     echo shar: error transmitting "'lib/sybperl.pl'" '(should have been 441 characters)'
  1127. fi
  1128. fi
  1129. chmod 444 lib/sybperl.pl
  1130. if test ! -d 't'
  1131. then
  1132.     mkdir 't'
  1133. fi
  1134. if test -f 't/sbex.pl'
  1135. then
  1136.     echo shar: will not over-write existing file "'t/sbex.pl'"
  1137. else
  1138.     echo x - 't/sbex.pl'
  1139.     sed 's/^X//' >'t/sbex.pl' << 'SHAR_EOF'
  1140. X#!../sybperl
  1141. X
  1142. X
  1143. X@nul = ('not null','null');
  1144. X@sysdb = ('master', 'model', 'tempdb');
  1145. X
  1146. Xrequire "../lib/sybperl.pl";
  1147. X
  1148. Xprint "Sybperl version $SybperlVer\n\n";
  1149. X
  1150. Xprint "This script tests some of sybperl's functions, and prints out\n";
  1151. Xprint "description of the databases that are defined in your Sybase\n";
  1152. Xprint "dataserver.\n\n";
  1153. X
  1154. X
  1155. X$dbproc = &dblogin("sa");    # Login to sybase
  1156. X
  1157. X$dbproc2 = &dbopen;        # Get a second dbprocess, so that we can select from several
  1158. X                                # chanels simultaneously. We could code things so that this
  1159. X                # feature is unnecessary, but it's good to exercise it.
  1160. X
  1161. X                # First, find out what databases exist:
  1162. X&dbcmd($dbproc, "select name from sysdatabases order by crdate\n");
  1163. X&dbsqlexec($dbproc);
  1164. X&dbresults($dbproc);
  1165. X
  1166. Xdatabase: while((@db = &dbnextrow($dbproc)))
  1167. X{
  1168. X    foreach $nm (@sysdb)
  1169. X    {
  1170. X    if($db[0] =~ /$nm/)
  1171. X    {
  1172. X        print "'$db[0]' is a system database\n";
  1173. X        next database;
  1174. X    }
  1175. X    }
  1176. X    print "Finding user tables in user database $db[0]...";
  1177. X
  1178. X    &dbcmd($dbproc2, "select o.name, u.name, o.id\n"); # 
  1179. X    &dbcmd($dbproc2, "from $db[0].dbo.sysobjects o, $db[0].dbo.sysusers u\n");
  1180. X    &dbcmd($dbproc2, "where o.type = 'U' and u.uid = o.uid\n");
  1181. X    &dbcmd($dbproc2, "order by o.name\n");
  1182. X
  1183. X    &dbsqlexec($dbproc2);
  1184. X    &dbresults($dbproc2);
  1185. X
  1186. X    while((@dat = &dbnextrow($dbproc2)))
  1187. X    {
  1188. X    $tab = join('@', @dat);    # Save the information
  1189. X    push(@tables, $tab);    # for later use...
  1190. X    }
  1191. X    print "Done.\n";
  1192. X
  1193. X    print "Finding user defined datatypes in database $db[0]...\n";
  1194. X
  1195. X    &dbcmd($dbproc2, "select s.length,substring(s.name,1,30),substring(st.name,1,30)\n");
  1196. X    &dbcmd($dbproc2, "from   $db[0].dbo.systypes s, $db[0].dbo.systypes st\n");
  1197. X    &dbcmd($dbproc2, "where  st.type = s.type\n");
  1198. X    &dbcmd($dbproc2, "and s.usertype > 100 and st.usertype < 100 and st.usertype != 18\n");
  1199. X    &dbsqlexec($dbproc2);
  1200. X    &dbresults($dbproc2);
  1201. X
  1202. X    while((@dat = &dbnextrow($dbproc2)))
  1203. X    {
  1204. X    print "sp_addtype $dat[1],";
  1205. X    if ($dat[2] =~ /char|binary/)
  1206. X    {
  1207. X        print "'$dat[2]($dat[0])'";
  1208. X    }
  1209. X    else
  1210. X    {
  1211. X        print "$dat[2]";
  1212. X    }
  1213. X    print "\n";
  1214. X
  1215. X    }
  1216. X    print "Done.\n";
  1217. X
  1218. X    print "Now we find the table definition for each user table\nin database $db[0]...\n";
  1219. X
  1220. X    foreach $ln (@tables)        # For each line in the list
  1221. X    {
  1222. X    @tab = split('@',$ln);
  1223. X
  1224. X    &dbcmd($dbproc2, "select Column_name = c.name, \n");
  1225. X    &dbcmd($dbproc2, "       Type = t.name, \n");
  1226. X    &dbcmd($dbproc2, "       Length = c.length, \n");
  1227. X    &dbcmd($dbproc2, "       Nulls = convert(bit, (c.status & 8))\n");
  1228. X    &dbcmd($dbproc2, "from   $db[0].dbo.syscolumns c, $db[0].dbo.systypes t\n");
  1229. X    &dbcmd($dbproc2, "where  c.id = $tab[2]\n");
  1230. X    &dbcmd($dbproc2, "and    c.usertype *= t.usertype\n");
  1231. X    
  1232. X    &dbsqlexec($dbproc2);
  1233. X    &dbresults($dbproc2);
  1234. X
  1235. X    print "\nTABLE $db[0].$tab[1].$tab[0]\n ("; 
  1236. X    $first = 1;
  1237. X    while((@field = &dbnextrow($dbproc2)))
  1238. X    {
  1239. X        print ",\n" if !$first;        # add a , and a \n if not first field in table
  1240. X        
  1241. X        print "\t$field[0] \t$field[1]";
  1242. X        print "($field[2])" if $field[1] =~ /char|bin/;
  1243. X        print " $nul[$field[3]]";
  1244. X
  1245. X        $first = 0 if $first;
  1246. X    }
  1247. X    print " )\n";
  1248. X
  1249. X# now get the indexes...
  1250. X#
  1251. X    print "\nIndexes on $db[0].$tab[0].$tab[1]...\n\n";
  1252. X    &dbuse($dbproc2, $db[0]);
  1253. X    &dbcmd($dbproc2, "sp_helpindex '$tab[1].$tab[0]'\n");
  1254. X
  1255. X    &dbsqlexec($dbproc2);
  1256. X    &dbresults($dbproc2);
  1257. X
  1258. X    while((@field = &dbnextrow($dbproc2)))
  1259. X    {
  1260. X        print "unique " if $field[1] =~ /unique/;
  1261. X        print "clustered " if $field[1] =~ /^clust/;
  1262. X        print "index $field[0]\n";
  1263. X        @col = split(/,/,$field[2]);
  1264. X        print "on $db[0].$tab[1].$tab[0] (";
  1265. X        $first = 1;
  1266. X        foreach $ln1 (@col)
  1267. X        {
  1268. X        print ", " if !$first;
  1269. X        $first = 0;
  1270. X        print "$ln1";
  1271. X        }
  1272. X        print ")\n";
  1273. X    }
  1274. X    print "\nDone.\n";
  1275. X    }
  1276. X    &dbuse($dbproc2, "master");
  1277. X    @tables = ();
  1278. X}
  1279. X
  1280. X&dbexit;
  1281.  
  1282. SHAR_EOF
  1283. if test 3784 -ne "`wc -c < 't/sbex.pl'`"
  1284. then
  1285.     echo shar: error transmitting "'t/sbex.pl'" '(should have been 3784 characters)'
  1286. fi
  1287. fi
  1288. chmod 775 t/sbex.pl
  1289. echo Done
  1290. exit 0
  1291.  
  1292. exit 0 # Just in case...
  1293. -- 
  1294. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1295. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1296. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1297. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1298.